package com.example.demo.common.service;

import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.example.demo.common.entity.pojo.BaseEntityPoJo;
import com.example.demo.utils.SnowflakeIdWorker;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

/**
 * .
 *
 * @author Mei Ruoxiao
 * @since 2020/9/10
 */
@Deprecated
public interface InsertService<T extends BaseEntityPoJo> {

    @Transactional(rollbackFor = {Exception.class})
    default T create(T t) throws RuntimeException {
        t.setId(SnowflakeIdWorker.getId());
        this.getRepository().insert(t);
        return t;
    }


    @Transactional(rollbackFor = {Exception.class})
    default List<T> createBatch(List<T> ts) throws RuntimeException {
        if (CollectionUtils.isEmpty(ts)) {
            return Collections.emptyList();
        } else {
            String sqlStatement = this.sqlStatement(SqlMethod.INSERT_ONE);
            int size = ts.size();
            this.executeBatch((sqlSession) -> {
                AtomicInteger i = new AtomicInteger(1);
                ts.forEach((t) -> {
                    t.setId(SnowflakeIdWorker.getId());
                    sqlSession.insert(sqlStatement, t);
                    if (i.get() % 50 == 0 || i.get() == size) {
                        sqlSession.flushStatements();
                    }
                    i.getAndIncrement();
                });
            });
            return ts;
        }
    }

    default String sqlStatement(SqlMethod sqlMethod) {
        return SqlHelper.table(currentModelClass()).getSqlStatement(sqlMethod.getMethod());
    }

    default Class<T> currentModelClass() {
        return (Class<T>) ReflectionKit.getSuperClassGenericType(getClass(), 1);
    }

    default void executeBatch(Consumer<SqlSession> consumer) {
        Class<T> tClass = currentModelClass();
        SqlHelper.clearCache(tClass);
        SqlSessionFactory sqlSessionFactory = SqlHelper.sqlSessionFactory(tClass);
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

        try {
            consumer.accept(sqlSession);
            sqlSession.commit();
        } catch (Throwable var11) {
            sqlSession.rollback();
            Throwable unwrapped = ExceptionUtil.unwrapThrowable(var11);
            if (unwrapped instanceof RuntimeException) {
                MyBatisExceptionTranslator myBatisExceptionTranslator = new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
                throw Objects.requireNonNull(myBatisExceptionTranslator.translateExceptionIfPossible((RuntimeException) unwrapped));
            }

            throw ExceptionUtils.mpe(unwrapped);
        } finally {
            sqlSession.close();
        }

    }

    <U extends BaseMapper<T>> U getRepository() throws RuntimeException;
}
